package com.dge.common.utils

import android.app.Activity
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.webkit.WebView
import androidx.core.net.toUri
import com.blankj.utilcode.util.UriUtils
import com.dge.common.R
import com.dge.common.base.view.BaseActivity
import com.dge.common.common.AppConfig
import com.dge.common.dialog.SelectedFileSourceDialog
import com.dge.common.extentions.isValid
import com.dge.common.extentions.string
import com.dge.common.other.IOSStyleDialogAnimator
import com.dge.common.other.PermissionCallback
import com.dge.common.other.glide.GlideEngine
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.hjq.toast.ToastUtils
import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.config.SelectModeConfig
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.lxj.xpopup.XPopup
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.File
import kotlin.math.absoluteValue

/**
 * @auther Jasper Jiao
 * @time 2023/1/5 10:03
 * @des webview一些回调方法
 */
object WebViewUtils {
    /**
     * 打开系统文件选择器
     */
    fun openSystemFileChooser(
        activity: BaseActivity<*>,
        mimeTypeList: Array<String>?,
        multipleSelect: Boolean,
        intent: Intent,
        title: CharSequence?,
        callback: (uris: Array<Uri>?) -> Unit
    ) {
        var containsPicture = false
        var containsVideo = false
        var containsFile = false
        val imageTypes = ArrayList<String>()
        val videoTypes = ArrayList<String>()
        val currentMineTypes = mimeTypeList?.filter { it.isValid() }?.toMutableList()
        mimeTypeList?.let {
            it.forEach { s ->
                FileUtil.MIME_MapTable.forEach { judge ->
                    if (judge[0] == s) {
                        currentMineTypes?.add(judge[1])
                    }
                }
            }
        }
        val mimeTypes = currentMineTypes?.toTypedArray()
        Timber.i("openSystemFileChooser mimeTypes.size = ${mimeTypes?.size}")
        if (mimeTypes != null && mimeTypes.size == 1 && mimeTypes[0].contains(",")) {
            val types = mimeTypes[0].split(",")
            types.forEach {
                if (it.contains("image/")) {
                    containsPicture = true
                    imageTypes.add(it)
                } else if (it.contains("video/")) {
                    containsVideo = true
                    videoTypes.add(it)
                } else containsFile = true
                Timber.i("openSystemFileChooser mimeTypes.size == 1 type = $it")
            }
        } else {
            mimeTypes?.forEach {
                if (it.contains("image/")) {
                    containsPicture = true
                    imageTypes.add(it)
                } else if (it.contains("video/")) {
                    containsVideo = true
                    videoTypes.add(it)
                } else containsFile = true
                Timber.i("openSystemFileChooser params mimeType = $it")
            }
        }
        var imageMimeTypes: Array<String>? = null
        if (containsPicture) {
            imageMimeTypes = Array(imageTypes.size) { "" }
            imageTypes.forEachIndexed { index, s ->
                imageMimeTypes[index] = s
            }
        }
        var videoMimeTypes: Array<String>? = null
        if (containsVideo) {
            videoMimeTypes = Array(videoTypes.size) { "" }
            videoTypes.forEachIndexed { index, s ->
                videoMimeTypes[index] = s
            }
        }

        XPopup.Builder(activity)
            .isDarkTheme(AppConfig.isDarkTheme())
            .asCustom(
                SelectedFileSourceDialog(
                    activity,
                    selectPhoto = if (!containsPicture) null else {
                        {
                            val module =
                                PictureSelector.create(activity).openGallery(SelectMimeType.ofImage())
                            if (imageMimeTypes != null && imageMimeTypes.isNotEmpty() && !imageMimeTypes.contains("image/*")) {
                                module.setQueryOnlyMimeType(*imageMimeTypes)
                            }
                            if (multipleSelect) {
                                module.setMaxSelectNum(Int.MAX_VALUE)
                            } else {
                                module.setSelectionMode(SelectModeConfig.SINGLE)
                                module.isDirectReturnSingle(true)// 单选时是否立即返回
                            }
                            module.isDisplayCamera(true)
                                .setImageEngine(GlideEngine.createGlideEngine())// 外部传入图片加载引擎，必传项
                                .forResult(object : OnResultCallbackListener<LocalMedia> {
                                    override fun onResult(result: java.util.ArrayList<LocalMedia>?) {
                                        Timber.i("compress result.size = ${result?.size}")
                                        if (result == null || result.isEmpty()) {
                                            callback(null)
                                            ToastUtils.show("发生错误，图片为空")
                                            return
                                        }
                                        activity.showLoading()
                                        val urls: MutableList<String> = ArrayList(result.size)
                                        for (media in result) {
                                            val path = PathUtils.getPath(media)
                                            if (path.isValid())
                                                urls.add(path)
                                        }

                                        if (urls.isEmpty()) {
                                            activity.hideLoading()
                                            callback(null)
                                            ToastUtils.show("图片地址为空")
                                            return
                                        }
                                        Timber.i("compress urls.size = ${urls.size}")
                                        activity.launch(Dispatchers.IO) {
                                            val fileList = ArrayList<File>()
                                            urls.forEach {
                                                val file = getFileFromUri(activity, it.toUri())
                                                fileList.add(file)
                                            }
                                            Timber.i("compress fileList.size = ${fileList.size}")
                                            withContext(Dispatchers.Main) {
                                                CompressUtils.compress(activity, fileList) { compressedList ->
                                                    Timber.i("compress finish size = ${compressedList.size}")
                                                    val uris: MutableList<Uri> = ArrayList(compressedList.size)
                                                    compressedList.forEach { file ->
                                                        val uri = Uri.fromFile(file)
                                                        uris.add(uri)
                                                        Timber.i("compress finish uri = $uri")
                                                    }
                                                    Timber.i("compress finish uris.size = ${uris.size}")
                                                    callback(uris.toTypedArray())
                                                    activity.hideLoading()
                                                }
                                            }
                                        }
                                    }

                                    override fun onCancel() {
                                        callback(null)
                                    }
                                })
                        }
                    },
                    selectVideo = if (!containsVideo) null else {
                        {
                            val module =
                                PictureSelector.create(activity).openGallery(SelectMimeType.ofVideo())
                            if (videoMimeTypes != null && videoMimeTypes.isNotEmpty() && !videoMimeTypes.contains("video/*")) {
                                module.setQueryOnlyMimeType(*videoMimeTypes)
                            }
                            if (multipleSelect) {
                                module.setMaxSelectNum(Int.MAX_VALUE)
                            } else {
                                module.setSelectionMode(SelectModeConfig.SINGLE)
                                module.isDirectReturnSingle(true)// 单选时是否立即返回
                            }
                            module.isDisplayCamera(true)
                                .setImageEngine(GlideEngine.createGlideEngine())// 外部传入图片加载引擎，必传项
                                .forResult(object : OnResultCallbackListener<LocalMedia> {
                                    override fun onResult(result: java.util.ArrayList<LocalMedia>?) {
                                        if (result == null || result.isEmpty()) {
                                            callback(null)
                                            ToastUtils.show("发生错误，视频地址为空")
                                            return
                                        }
                                        activity.showLoading()
                                        val urls: MutableList<String> = ArrayList(result.size)
                                        for (media in result) {
                                            val path = PathUtils.getPath(media)
                                            if (path.isValid())
                                                urls.add(path)
                                        }

                                        if (urls.isEmpty()) {
                                            activity.hideLoading()
                                            callback(null)
                                            ToastUtils.show("视频地址为空")
                                            return
                                        }
                                        activity.launch(Dispatchers.IO) {
                                            val fileList = ArrayList<File>()
                                            val uris: MutableList<Uri> = ArrayList(urls.size)
                                            urls.forEach {
                                                val file = getFileFromUri(activity, it.toUri())
                                                fileList.add(file)
                                                for (item in fileList) {
                                                    val uri: Uri = Uri.fromFile(item)
                                                    uris.add(uri)
                                                    Timber.i("video: $uri")
                                                }
                                            }
                                            withContext(Dispatchers.Main) {
                                                activity.hideLoading()
                                                callback(uris.toTypedArray())
                                            }
                                        }
                                    }

                                    override fun onCancel() {
                                        callback(null)
                                    }
                                })
                        }
                    },
                    selectFile = if (!containsFile) null else {
                        {
                            intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
                            intent.type = "*/*"
                            // 是否是多选模式
                            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multipleSelect)
                            activity.startActivityForResult(Intent.createChooser(intent, title ?: "选择文件"), object :
                                BaseActivity.OnActivityCallback {
                                override fun onActivityResult(resultCode: Int, data: Intent?) {
                                    val uris: MutableList<Uri> = ArrayList()
                                    if (resultCode == Activity.RESULT_OK && data != null) {
                                        val uri = data.data
                                        if (uri != null) {
                                            // 如果用户只选择了一个文件
                                            val isImage = isImage(activity, uri)
                                            if (isImage) {
                                                activity.launch(Dispatchers.IO) {
                                                    val file = getFileFromUri(activity, uri)
                                                    Timber.i("compress file.path = ${file.absolutePath}")
                                                    withContext(Dispatchers.Main) {
                                                        CompressUtils.compress(activity, file) { file ->
                                                            val compressedUri = Uri.fromFile(file)
                                                            uris.add(compressedUri)
                                                            Timber.i("compress finish uri = $compressedUri")
                                                            callback(uris.toTypedArray())
                                                            activity.hideLoading()
                                                        }
                                                    }
                                                }
                                            } else {
                                                uris.add(uri)
                                                callback(uris.toTypedArray())
                                            }
                                        } else {
                                            val imageUriList = ArrayList<Uri>()
                                            // 如果用户选择了多个文件
                                            val clipData = data.clipData
                                            if (clipData != null) {
                                                for (i in 0 until clipData.itemCount) {
                                                    val itemUri = clipData.getItemAt(i).uri
                                                    val isImage = isImage(activity, itemUri)
                                                    if (isImage) {
                                                        imageUriList.add(itemUri)
                                                    } else {
                                                        uris.add(itemUri)
                                                    }
                                                }
                                                if (imageUriList.isNotEmpty()) {
                                                    activity.launch(Dispatchers.IO) {
                                                        val fileList = ArrayList<File>()
                                                        imageUriList.forEach {
                                                            val file = getFileFromUri(activity, it)
                                                            fileList.add(file)
                                                        }
                                                        Timber.i("compress fileList.size = ${fileList.size}")
                                                        withContext(Dispatchers.Main) {
                                                            CompressUtils.compress(
                                                                activity,
                                                                fileList
                                                            ) { compressedList ->
                                                                Timber.i("compress finish size = ${compressedList.size}")
                                                                compressedList.forEach { file ->
                                                                    val itemUri = Uri.fromFile(file)
                                                                    uris.add(itemUri)
                                                                    Timber.i("compress finish uri = $itemUri")
                                                                }
                                                                Timber.i("compress finish uris.size = ${uris.size}")
                                                                activity.hideLoading()
                                                                callback(uris.toTypedArray())
                                                            }
                                                        }
                                                    }
                                                } else {
                                                    callback(uris.toTypedArray())
                                                }
                                            } else {
                                                callback(uris.toTypedArray())
                                            }
                                        }
                                    } else {
                                        // 不管用户最后有没有选择文件，最后必须要调用 onReceiveValue，如果没有调用就会导致网页再次点击上传无响应
                                        callback(uris.toTypedArray())
                                    }
                                }
                            })
                        }
                    },
                    onDismissWithSelectNull = {
                        // 不管用户最后有没有选择文件，最后必须要调用 onReceiveValue，如果没有调用就会导致网页再次点击上传无响应
                        callback(null)
                    }
                )
            ).show()
    }

    private fun getFileFromUri(activity: BaseActivity<*>, uri: Uri): File {
        var file = UriUtils.uri2FileNoCacheCopy(uri)
        if (file == null || !file.exists()) {
            var randomInt = FileUtil.random.nextInt()
            randomInt =
                if (randomInt > 0) randomInt else randomInt.absoluteValue
            file = FileUtil.getFileFromContentUri(
                activity, uri, "${randomInt}.png"
            )
        }
        return file
    }

    /**
     * 弹出需要定位权限dialog
     */
    fun onGeolocationPermissionsShowPrompt(activity: Activity, callback: (arg1: Boolean, arg2: Boolean) -> Unit) {
        XPopup.Builder(activity)
            .isDarkTheme(AppConfig.isDarkTheme())
            .customAnimator(IOSStyleDialogAnimator())
            .asConfirm(
                "",
                R.string.common_web_location_permission_title.string(),
                R.string.common_web_location_permission_reject.string(),
                R.string.common_web_location_permission_allow.string(),
                {
                    XXPermissions.with(activity)
                        .permission(Permission.ACCESS_FINE_LOCATION)
                        .permission(Permission.ACCESS_COARSE_LOCATION)
                        .request(object : PermissionCallback() {
                            override fun onGranted(
                                permissions: MutableList<String>,
                                all: Boolean
                            ) {
                                if (all) {
                                    callback(true, true)
                                }
                            }
                        })
                },
                {
                    callback(false, true)
                },
                false
            ).show()
    }

    /**
     * 跳转到拨号界面
     */
    private fun dialing(context: Context, url: String) {
        XPopup.Builder(context)
            .isDarkTheme(AppConfig.isDarkTheme())
            .customAnimator(IOSStyleDialogAnimator())
            .asConfirm(
                "", String.format(
                    R.string.common_web_call_phone_title.string(),
                    url.replace("tel:", "")
                ),
                R.string.common_web_call_phone_reject.string(), R.string.common_web_call_phone_allow.string(),
                {
                    try {
                        val intent = Intent(Intent.ACTION_DIAL)
                        intent.data = Uri.parse(url)
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        context.startActivity(intent)
                    } catch (e: Exception) {
                        ToastUtils.show("页面未找到")
                    }
                }, null, false
            ).show()
    }

    /**
     * 跳转到其他链接
     */
    fun shouldOverrideUrlLoading(view: WebView, url: String, callback: (url: String) -> Unit): Boolean {
        Timber.i("WebView shouldOverrideUrlLoading：${url}")
        val scheme: String = Uri.parse(url).scheme ?: return false
        when (scheme) {
            "http", "https" -> view.loadUrl(url)
            "tel" -> dialing(view.context, url)
            else -> {
                //使用，默认浏览器打开
                try {
                    val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
                    if (view.context !is Activity)
                        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                    view.context.startActivity(intent)
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        }
        return true
    }

    /**
     * 网页弹出警告框
     */
    fun onJsAlert(context: Context, message: String, onConfirm: () -> Unit) {
        XPopup.Builder(context)
            .isDarkTheme(AppConfig.isDarkTheme())
            .customAnimator(IOSStyleDialogAnimator())
            .dismissOnBackPressed(false)
            .dismissOnBackPressed(false)
            .asConfirm(
                "", message, "", "确定", {
                    onConfirm()
                }, null, true
            ).show()
    }

    /**
     * 网页弹出确定取消框
     */
    fun onJsConfirm(context: Context, message: String, onConfirm: (isConfirm: Boolean) -> Unit) {
        XPopup.Builder(context)
            .isDarkTheme(AppConfig.isDarkTheme())
            .customAnimator(IOSStyleDialogAnimator())
            .dismissOnBackPressed(false)
            .dismissOnBackPressed(false)
            .asConfirm("", message, {
                onConfirm(true)
            }, {
                onConfirm(false)
            }).show()
    }

    /**
     * 网页弹出输入框
     */
    fun onJsPrompt(context: Context, defaultValue: String, onConfirm: (isConfirm: Boolean, result: String) -> Unit) {
        XPopup.Builder(context)
            .isDarkTheme(AppConfig.isDarkTheme())
            .customAnimator(IOSStyleDialogAnimator())
            .dismissOnBackPressed(false)
            .dismissOnBackPressed(false)
            .asInputConfirm("", "", defaultValue, "", {
                onConfirm(true, it)
            }, {
                onConfirm(false, "")
            }, 0).show()
    }

    /**
     * 网站证书校验错误
     */
    inline fun onReceivedSslError(context: Context, crossinline onConfirm: (isConfirm: Boolean) -> Unit) {
        // 如何处理应用中的 WebView SSL 错误处理程序提醒：https://support.google.com/faqs/answer/7071387?hl=zh-Hans
        XPopup.Builder(context)
            .isDarkTheme(AppConfig.isDarkTheme())
            .customAnimator(IOSStyleDialogAnimator())
            .asConfirm(
                "", R.string.common_web_ssl_error_title.string(),
                R.string.common_web_ssl_error_reject.string(), R.string.common_web_ssl_error_allow.string(),
                {
                    onConfirm(true)
                }, {
                    onConfirm(false)
                }, false
            ).show()
    }

    private fun isImage(context: Context, uri: Uri): Boolean {
        val resolver: ContentResolver = context.contentResolver
        val mimeType = resolver.getType(uri)
        Timber.i("mimeType = $mimeType")
        return mimeType?.startsWith("image/") == true
    }
}